package com.markhsiu.mysql;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import com.markhsiu.mysql.cmd.CommonCMD;
import com.markhsiu.mysql.packet.MySQLMessage;
import com.markhsiu.mysql.packet.client.AuthPacket;
import com.markhsiu.mysql.packet.client.QueryPacket;
import com.markhsiu.mysql.packet.server.HandshakePacket;
import com.markhsiu.mysql.session.Session;
import com.markhsiu.mysql.session.Session.AUTH_STATUS;

public class MysqlClient {

	private static final String hostname = "192.168.101.73";
	private static final int port = 3306;
	private static final String userName = "root";
	private static final String password = "root";
	private static final String dataBase = "b2b";
	private SocketChannel socketChannel;
	private Selector selector;
	
	public static void main(String[] args)  {
		 MysqlClient client = new MysqlClient();
		
		 try {
			 client.init();
			 client.start();
		} catch (Exception e) {
			client.stop();
			e.printStackTrace();
		}
	}
	
	
	public void init() throws IOException{
		InetSocketAddress remote = new InetSocketAddress(hostname, port);
		socketChannel = SocketChannel.open();
		selector = Selector.open();
		
		socketChannel.configureBlocking(false);
		socketChannel.connect(remote);
//		while(!socketChannel.finishConnect()){
//			System.out.println(" cannot connection to ..");
//		} 
		
		Session session = new Session();
		Connection connection = new Connection();
		connection.ip = hostname;
		connection.port = port;
		connection.userName = userName;
		connection.passord = password;
		connection.dataBase = dataBase;
		session.authed = AUTH_STATUS.NO;
		session.connection = connection;
		
		socketChannel.register(selector, SelectionKey.OP_CONNECT,session);
		
		
		System.out.println("connection success"); 
	}
	
	public void start(){
		while(true){
			try {
				int readyChannels = selector.select();
				if(readyChannels == 0){
					TimeUnit.MILLISECONDS.sleep(100);
					continue;
				}
				
				Set<SelectionKey> selectionKeys = selector.selectedKeys();
				Iterator<SelectionKey> keyIterator = selectionKeys.iterator();
				while(keyIterator.hasNext()){
					SelectionKey key = keyIterator.next();
					if (!key.isValid()) {
                        continue;
                    }
					
					if(key.isAcceptable()){
						System.out.println("a connection was accepted by a ServerSocketChannel.");
						doAccept(key);
					} else if(key.isConnectable()){
						System.out.println("a connection was established with a remote server.");
						doConnection(key);
					} else if(key.isReadable()){
						System.out.println("a channel is ready for reading");
						doRead(key);
					} else if(key.isWritable()){
						System.out.println("a channel is ready for writing");
						doWrite(key);
					}
					keyIterator.remove();
				}
			} catch (Exception e) {
				e.printStackTrace();
				break;
			}
		}
	}
	
	public void stop(){
		try {
			if(selector!=null && selector.isOpen()){
				selector.close();
			}
			if(socketChannel != null && socketChannel.isOpen()){
				socketChannel.close();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		
	}
	 

	public void doConnection(SelectionKey key){
		SocketChannel channel = (SocketChannel) key.channel();
		Session session = (Session) key.attachment();
		//如果SocketChannel在非阻塞模式下，此时调用connect()，该方法可能在连接建立之前就返回了。
		//为了确定连接是否建立，可以调用finishConnect()的方法
		if(channel.isConnectionPending()){
			try {
				channel.finishConnect();
				channel.register(selector, SelectionKey.OP_READ,session);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	public void doAccept(SelectionKey key){
		
	}
	
	public void doWrite(SelectionKey key){
		
	}
	
	public void doRead(SelectionKey key) throws IOException{
		SocketChannel channel = (SocketChannel) key.channel();
		
		Session session = (Session) key.attachment();
		ByteBuffer readBuffer = session.readBuffer;
		ByteBuffer writeBuffer = session.writeBuffer;
		readBuffer.clear();
		 
		while(channel.read(readBuffer) > 0){
			writeBuffer.clear();
			
			System.out.println("start ... read");
			readBuffer.flip(); 
			if(session.authed == AUTH_STATUS.NO){
				 MySQLMessage message = new MySQLMessage(readBuffer);
				 HandshakePacket packet = new HandshakePacket();
				 packet.read(message);
				 System.out.println(packet.descrption());
				 session.authed = AUTH_STATUS.ING;
				  
				 AuthPacket authPacket = new AuthPacket(packet);
				 authPacket.write(session);
				 channel.write(writeBuffer);
				 channel.register(selector, SelectionKey.OP_READ , session);
			} else if(session.authed == AUTH_STATUS.ING){
				print(readBuffer);
				byte flag = CommonCMD.COM_QUERY;
				byte[] queryStr = "select * from crm_public_resource limit 0,1".getBytes();
				QueryPacket packet = new QueryPacket(flag, queryStr);
				packet.write(session);
				channel.write(writeBuffer);
				session.authed = AUTH_STATUS.OK;
				channel.register(selector, SelectionKey.OP_READ , session);
				
			} else {
				print(readBuffer);
				System.out.println("OK ");
				key.cancel();
			}
		 
			readBuffer.clear();
			System.out.println("end ... read");
		}
		
	}
	
	private void print(ByteBuffer byteBuffer){
		System.out.println("print ==================================== ");
		MySQLMessage message = new MySQLMessage(byteBuffer);
		System.out.println(message.readUB3());
		System.out.println(message.read());
		byte[] data = new byte[byteBuffer.limit()-byteBuffer.position()];
		
		byteBuffer.get(data);
		System.out.println(new String(data));
		for(byte b : data){
			System.out.print(b+" ");
		}
		System.out.println("");
		System.out.println("print ==================================== ");
	}
}
